<?php
/**
 * Created by PhpStorm.
 * User: LiuJiaJun
 * Date: 2018/12/11
 * Time: 17:14
 */

namespace api\storage\service;


use api\storage\common\Constant;
use api\storage\model\CarSeatModel;
use api\storage\model\ClientModel;
use api\storage\model\SeatModel;
use service\logger\LoggerFactory;
use think\Cache;
use think\Exception;

class SocketService
{
    const TURN_ON_GREEN = 1; //亮绿灯
    const TURN_ON_RED = 2; //亮红灯
    const TURN_ON_YELLOW = 3; //亮黄灯
    const TURN_OFF_LIGHT = 0; //灭灯
    const SEND_DATA_URL = 'http://127.0.0.1:8092';

    /**
     * 发送灯指令的方式
     */
    const SEND_METHOD_DIRECT = 0;
    const SEND_METHOD_DB = 1;
    public static $logger;

    /**灯板指令：
     * TURN_ON_GREEN = 1; //亮绿灯
    * TURN_ON_RED = 2; //亮红灯
    * TURN_ON_YELLOW = 3; //亮黄灯
    * TURN_OFF_LIGHT = 0; //灭灯
     * @param array $codes
     * @param $storageUuid
     * @param int $status 灯的指令  0 灭灯；  1 亮红灯；  2亮绿灯；  3 亮黄灯； 4质检   5广播灭灯//不确定
     * @param int $method 发送指令的方式 0 直接发送，1 将灯的信息存储到数据库中
     * @return bool|string|null
     * @throws Exception
     */
    public static function send($codes = [], $storageUuid, $status = 1, $method = 0)
    {
        self::init();
        self::$logger->info('接受的数据：uuid' . $storageUuid . '，seatId：' . var_export($codes, true));
        if (empty($codes)) {
            return false;
        }
        if (is_string($codes) || is_numeric($codes)) {
            $codes = [$codes];
        }
        $codes = array_values(array_unique($codes));
        switch ($method) {
            case self::SEND_METHOD_DIRECT:
                return self::sendDirect($codes, $storageUuid, $status);
            case self::SEND_METHOD_DB:
                return self::sendToDb($codes, $storageUuid, $status);
            default:
                throw new Exception('不存在该发送指令的方式');
        }
    }

    /**
     * 直接发送命令码
     *
     * @param $codes
     * @param $storageUuid
     * @param $status
     * @return bool|string
     */
    public static function sendDirect($codes, $storageUuid, $status)
    {
        $uids = self::getUids($storageUuid);
        if (empty($uids)) {
            self::$logger->info("没有找到该仓库对应客户端的uid");
            return false;
        }
        $command = [];
        foreach ($codes as $item) {
            $command[]['code'] = self::makeCommand($item, $status);
        }
        $data = [
            'type' => 'send',
            'command' => json_encode($command),
            'uid' => json_encode($uids)
        ];
        self::$logger->info('发送给服务端的数据为：' . var_export($data, true));
        return self::cURL(self::SEND_DATA_URL, $data, 5);
    }

    /**
     * 将命令码存储到数据库中
     *
     * @param $codes
     * @param $storageUuid
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     *
     * @param $status
     * @return string
     */
    public static function sendToDb($codes, $storageUuid, $status)
    {
        $seatModel = new SeatModel();
        $i = 0;
        foreach ($codes as $code) {
            $res = $seatModel->updateCommandCode($code, $storageUuid, $status);
            $i++;
            if ($res === false) {
                self::$logger->info("第{$i}个seatId更新命令码有误，错误sql为：" . $seatModel->getLastSql());
                return 'fail';
            }
        }
        return 'ok';
    }

    /***修改小车站位表的command_code状态 1红灯 2绿灯 3蓝灯
     * @param $codes
     * @param $carId
     * @param $status
     * @return string
     */
    public static function carSendToDb($codes, $carId, $status)
    {
        $carSeatModel = new CarSeatModel();
        $i = 0;
        if (is_string($codes)) {
            $codes = [$codes];
        }
        foreach ($codes as $code) {
            $res = $carSeatModel->updateCommandCode($code, $carId, $status);//虽然写作$storageUuid，但此处传入的是car_uuid
            $i++;
            if ($res === false) {
                self::$logger->info("第{$i}个小车seat_code更新命令码有误，错误sql为：" . $carSeatModel->getLastSql());
                return 'fail';
            }
        }

    }

    /**
     * @param string $host
     * @param int $status 灯的指令  0 灭灯；  1 亮红灯；  2亮绿灯；  3 亮黄灯； 4质检  5广播灭灯
     * @return bool|string
     */
    public static function test($host = '0274', $status = 1)
    {
        self::init();
        for ($i = 0; $i <1; $i++) {
            $dec = dechex($i);
            $dec = strlen(strval($dec)) == 1 ? '0'.$dec : $dec;
            $codes[] = $host . $dec;
        }
        foreach ($codes as $item) {
            $command[]['code'] = self::makeCommand($item, $status);
            if ($status == 4 || $status == 5) {
                break;
            }
        }
        $data = [
            'type' => 'send',
            'command' => json_encode($command),
            'uid' => json_encode(['0020b6cf378d774ae4794d7aae3c9317'])
        ];
        self::$logger->error('接受到的数据：' . var_export($data, true));

        return self::cURL("http://127.0.0.1:8092", $data);
    }

    /**
     * 将seatId转换成指令
     * @param $word
     * @param int $code
     * @return string
     */
    private static function makeCommand($word, $code = 1)
    {
        $equipment = substr($word, 0, 4);
        //传过来的灯的信息是16进制
        $light = intval(hexdec(substr($word, 4, 2)));
        //一个字节的信息，包括命令和灯的信息
        $dataB = '';
        //返回一个完整的命令
        $command = '';
        if ($code === '') {
            return '灯的状态不能为空';
        }
        switch (intval($code)) {
            case 0:
                //十进制转为16进制
                $dataB = dechex($light);
                $hex = str_pad($dataB, 2, '0', STR_PAD_LEFT);
                $command = $equipment . '02' . $hex;
                break;
            case 1:
                $dataB = dechex(128 + $light);
                $hex = str_pad($dataB, 2, '0', STR_PAD_LEFT);
                $command = $equipment . '02' . $hex;
                break;
            case 2:
                $dataB = dechex(64 + $light);
                $hex = str_pad($dataB, 2, '0', STR_PAD_LEFT);
                $command = $equipment . '02' . $hex;
                break;
            case 3:
                $dataB = dechex(192 + $light);
                $hex = str_pad($dataB, 2, '0', STR_PAD_LEFT);
                $command = $equipment . '02' . $hex;
                break;
            case 4:
                $command = $equipment . '03';
                break;
            case 5:
                $command =  'ffff00';
        }
        return $command;
    }

    /**
     * 获取发送的uid信息
     *
     * @param $storageUuid
     * @return array|mixed
     */
    private static function getUids($storageUuid)
    {
        $cacheUid = Cache::get(Constant::CACHE_PREFIX_CLIENT . $storageUuid);
        if (empty($cacheUid)) {
            $clientModel = new ClientModel();
            $uids = $clientModel->queryUid($storageUuid);
            if (!empty($uids)) {
                Cache::set(Constant::CACHE_PREFIX_CLIENT . $storageUuid, $uids);
            }
            return $uids;
        }
        return $cacheUid;
    }

    private static function init()
    {
        if (empty(self::$logger)) {
            self::$logger = LoggerFactory::getLogger('socket');
        }
    }

    public static function cURL($url = 'http://127.0.0.1:5678', $data = null, $timeout = 0, $isProxy = false)
    {
        $urlArr = parse_url($url);
        $curl = curl_init();
        //如果设置的代理，那么进行代理处理
        if ($isProxy) {
            $proxy = '127.0.0.1';
            $proxyPort = '8001';
            curl_setopt($curl, CURLOPT_PROXY, $proxy . ':' . $proxyPort);
        }
        //设置url
        curl_setopt($curl, CURLOPT_URL, $url);
        //https 处理
        if ($urlArr['scheme'] == 'https') {
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        }
        //如果数据不为空的，进行post处理
        if (!empty($data)) {
            if (is_array($data)) {
                //如果是数组，把数组转成 key1=value1&key2=value2这样的形式
                $data = http_build_query($data);
            }
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array(
                'Cache-Control:no-cache',
                'Content-Type:application/x-www-form-urlencoded'
            ));
        }
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        //如果设置超时时间，那么进行处理
        if ($timeout > 0) {
            curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
        }
        $output = curl_exec($curl);
        $error = curl_errno($curl);
        curl_close($curl);
        if ($error) {
            return false;
        }
        return $output;
    }

    public static function fSockOpen($url, $data = [], $cookie = [])
    {
        $urlArr = parse_url($url);
        if (!isset($urlArr['host'])) {
            return false;
        }
        $port = isset($urlArr['port']) ? $urlArr['port'] : 80;
        if ($urlArr['scheme'] == 'https') {
            $urlArr['host'] = 'ssl://' . $urlArr['host'];
        }
        $fp = fsockopen($urlArr['host'], $port, $errno, $errStr, 30);
        if (!$fp) {
            return false;
        }
        $path = isset($urlArr['path']) ? $urlArr['path'] : '/index.php';
        $path .= isset($urlArr['query']) ? '?' . $urlArr['query'] : '';
        $method = empty($data) ? 'GET' : 'POST';
        $header = "$method $path HTTP/1.1\r\n";
        $header .= "Host: {$urlArr['host']}\r\n";
        if (!empty($cookie)) {
            $tmpCookie = strval(null);
            foreach ($cookie as $key => $value) {
                $tmpCookie .= $key . '=' . $value . ';';
            }
            $cookieStr = "Cookie: " . base64_encode($tmpCookie) . "\r\n";
            $header .= $cookieStr;
        }
        if (!empty($data)) {
            $tmpPost = [];
            foreach ($data as $key => $value) {
                $tmpPost[] = $key . '=' . urlencode($value);
            }
            $tmpPost = implode('&', $tmpPost);
            $postStr = "Content-Type:application/x-www-form-urlencoded; charset=UTF-8\r\n";
            $postStr .= "Content-Length: " . strlen($tmpPost) . "\r\n";
            $postStr .= "Connection:Close\r\n\r\n";
            $postStr .= $tmpPost;
            $header .= $postStr;
        } else {
            $header .= "Connection:Close\r\n\r\n";
        }
        fwrite($fp, $header);
        //延迟一会儿，不然有可能在nginx服务器上无法执行成功
        usleep(1000);
        fclose($fp);
        return true;
    }

}